package com.tc.quartz.server.job.base;

import com.tc.quartz.server.core.StatusEnum;
import com.tc.quartz.server.exception.JobRunException;
import com.tc.quartz.util.QrtzUtil;
import org.apache.commons.lang3.StringUtils;
import org.quartz.JobExecutionContext;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;
import java.util.Map;

/**
 * 代理job基类
 * @author yongjin.ye
 *
 */
public abstract class BaseProxyJob extends BaseJob {

	//jobDataMap传递过来的变量名称（名称为固定值）
	static final String PROXY_CLASS_NAME = "PROXY_CLASS_NAME";
	static final String PROXY_METHOD_NAME = "PROXY_METHOD_NAME";
	
	@Override
	public Object doExecute(JobExecutionContext context) throws Exception {
		try {
			// 从job中获取参数
			String className = context.getJobDetail().getJobDataMap().getString(PROXY_CLASS_NAME);
			String methodName = context.getJobDetail().getJobDataMap().getString(PROXY_METHOD_NAME);
			log.info("定时任务[{}]执行开始，参数：className={}， methodName={}", context.getJobDetail().getKey().getName(), className, methodName);
			if(StringUtils.isBlank(className) || StringUtils.isBlank(methodName)){
				throw new JobRunException(StatusEnum.ERR_NO_PROXY_PARAMS);
			}
			// 获取对象
			Class<?> clazz = Class.forName(className);
			Object beanObj = this.getObjectByClass(clazz);
			//优先查找带有map参数的方法
			Method method = null;
			Object invokeResult = null;
			if (null != (method = ReflectionUtils.findMethod(clazz, methodName, Map.class, Map.class))) {
				invokeResult = ReflectionUtils.invokeMethod(method, beanObj, context.getJobDetail().getJobDataMap(), context.getTrigger().getJobDataMap());
			} else if (null != (method = ReflectionUtils.findMethod(clazz, methodName, Map.class))) {
				invokeResult = ReflectionUtils.invokeMethod(method, beanObj, context.getMergedJobDataMap());
			} else if (null != (method = ReflectionUtils.findMethod(clazz, methodName))) {
				invokeResult = ReflectionUtils.invokeMethod(method, beanObj);
			} else {
				this.jobRunLog.append(String.format("ClassMethod信息：%s", QrtzUtil.obj2string(ReflectionUtils.getAllDeclaredMethods(clazz))));
				throw new JobRunException(StatusEnum.ERR_NO_METHOD_FOUND, className, methodName);
			}
			return invokeResult;
		} catch (InstantiationException e) {
			throw new JobRunException(StatusEnum.ERR_INSTANTIATION, e);
		} catch (IllegalAccessException e) {
			throw new JobRunException(StatusEnum.ERR_ILLEGAL_ACCESS, e);
		} catch (ClassNotFoundException e) {
			throw new JobRunException(StatusEnum.ERR_NO_CLASS_FOUND, e);
		} catch (Exception e) {
			throw e;
		}
	}

	/**
	 * 根据CLASS名称 获取对象，优先从springBean中获取，获取不到则new一个对象。
	 * 
	 * @param className
	 * @return
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws ClassNotFoundException
	 */
	private Object getObjectByClass(Class<?> jobClazz) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
		try {
			Object springBeanObj = this.getSpringBean(jobClazz);
			if (null != springBeanObj) {
				return springBeanObj;
			}
		} catch (Exception e) {
			log.info("定时任务获取spring-bean异常。", e);
		}
		log.info("定时任务获取spring-bean失败，准备根据class初始化对象。");
		return jobClazz.newInstance();
	}

}
